package com.black.utils.commons.pool;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;


/**
 * @author ylx
 */
@Slf4j
public abstract class PoolFactory<T> implements PooledObjectFactory<T> {
    protected PoolProperties poolProperties;

    public PoolFactory(PoolProperties poolProperties) {
        this.poolProperties = poolProperties;
    }

    public void updateConfig() {
        poolProperties.updateConfig();
    }

    /**
     * 创建新对象并封装到 DefaultPooledObject 返回
     *
     * @return PooledObject 池化对象实例
     */
    @Override
    public PooledObject<T> makeObject() {
        try {
            T object = make();
            log.info("make {}", object.getClass().getSimpleName());
            return new DefaultPooledObject<>(object);
        } catch (Exception e) {
            log.error("make error:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建新对象并返回 封装到 DefaultPooledObject
     *
     * @return 对象实例
     * @throws Exception 创建对象异常
     */
    public abstract T make() throws Exception;

    /**
     * 销毁池中的对象。
     * 当对象不再需要使用并且将从池中移除时，此方法被调用。它的目的是释放对象所占用的资源，
     * 如关闭连接，以便对象可以被安全地垃圾回收。
     *
     * @param pooledObject 包装了对象的PooledObject实例。
     *                     通过此参数获取实际的实例进行操作。
     */
    @Override
    public void destroyObject(PooledObject<T> pooledObject) {
        T object = getObject(pooledObject);
        String simpleName = object.getClass().getSimpleName();
        log.info("destroy {}", simpleName);
        try {
            destroy(object);
        } catch (Exception e) {
            log.error("destroy {} error: {}", simpleName, e.getMessage());
        }
    }

    /**
     * 销毁池中的对象。
     * 当对象不再需要使用并且将从池中移除时，此方法被调用。它的目的是释放对象所占用的资源，
     * 如关闭连接，以便对象可以被安全地垃圾回收。
     *
     * @param object 对象实例
     * @throws Exception 销毁异常
     */
    public abstract void destroy(T object) throws Exception;

    /**
     * 验证对象是否有效。
     * 该方法根据配置 可在借出和归还时调用
     * 用于检查池中的对象是否仍然正常。
     *
     * @param pooledObject 包装了对象的PooledObject实例。
     *                     通过此参数获取实际的实例进行操作。
     * @return 如果对象有效则返回true，否则返回false。
     */
    @Override
    public boolean validateObject(PooledObject<T> pooledObject) {
        T object = getObject(pooledObject);
        String simpleName = object.getClass().getSimpleName();
        try {
            return validate(object);
        } catch (Exception e) {
            log.error("validate {} error: {}", simpleName, e.getMessage());
        }
        return false;
    }

    /**
     * 验证对象是否有效。
     * 该方法根据配置 可在借出和归还时调用
     * 用于检查池中的对象是否仍然正常。
     *
     * @param object 对象实例
     * @return 如果对象有效则返回true，否则返回false。
     */
    public abstract boolean validate(T object) throws Exception;

    /**
     * 激活对象。该方法在对象从池中取出并使用前调用，
     *
     * @param pooledObject 包装PooledObject对象。
     *                     通过此参数获取实际的实例进行操作。
     */
    @Override
    public void activateObject(PooledObject<T> pooledObject) {
        T object = getObject(pooledObject);
        String simpleName = object.getClass().getSimpleName();
        try {
            active(object);
        } catch (Exception e) {
            log.error("active {} error {}", simpleName, e.getMessage());
        }
    }

    /**
     * 激活对象。该方法在对象从池中取出并使用前调用，
     *
     * @param object 对象实例
     * @throws Exception 激活异常
     */
    public abstract void active(T object) throws Exception;

    /**
     * 将对象置于非活动状态。此方法在对象从池中取出使用后返回池中时被调用。
     * 主要用于在对象返回池中前进行一些必要的检查或重置工作。
     *
     * @param pooledObject 包装了实例的PooledObject对象。
     *                     通过此参数获取实际的实例进行操作。
     */
    @Override
    public void passivateObject(PooledObject<T> pooledObject) {
        T object = getObject(pooledObject);
        String simpleName = object.getClass().getSimpleName();
        try {
            passivate(object);
        } catch (Exception e) {
            log.error("passivate {} error {}", simpleName, e.getMessage());
        }
    }

    /**
     * 将对象置于非活动状态。此方法在对象从池中取出使用后返回池中时被调用。
     * 主要用于在对象返回池中前进行一些必要的检查或重置工作。
     *
     * @param object 对象实例
     * @throws Exception 钝化异常
     */
    public abstract void passivate(T object) throws Exception;

    /**
     * 从池中获取 T Object 对象。
     * <p>
     * 此方法用于从 T Object 池中获取一个可用的 T Object 实例。如果提供的PooledObject参数为null，
     * 则方法会直接返回null；否则，它将返回PooledObject封装的 T Object 实例。
     * 这个方法是池管理 T Object 实例的核心方法之一，它确保了只有有效的 T Object 实例被使用。
     *
     * @param pooledObject 包含 T Object 实例的PooledObject对象。如果为null，则无法获取 T Object 实例。
     * @return T Object 实例，如果输入参数为null，则返回null。
     */
    protected T getObject(PooledObject<T> pooledObject) {
        // 检查输入参数是否为null
        if (null == pooledObject) {
            throw new NullPointerException("getObject error pooledObject is null");
        }
        T object = pooledObject.getObject();
        if (null == object) {
            throw new NullPointerException("getObject error object is null");
        }
        // 从PooledObject中获取FTPClient实例
        return object;
    }
}
